<!DOCTYPE html>
<html lang="zh-cn">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="robots" content="noodp" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
        <title>Redis - 我的Hugo博客</title><meta name="Description" content=""><meta property="og:title" content="Redis" />
<meta property="og:description" content="Redis 去官网上下载redis linux版本的
tar -zxvf 解压redis，然后进入这个解压文件的目录执行make命令 然后再make install
默认安装在usr/local/bin
在usr/local/bin下新建一个myconfig文件夹 mkdir myconfig
然后把redis下的config复制到usr/local/bin/myconfig
redis-server myconfig/redis.conf
redis-cli -p 6379
redis-cli shutdown
redis-check-aof &ndash;fix appendonlu.aof 需要在配置文件中开启aof
ps -ef|grep redis 查看redis进程状态
五大数据类型 String  String
 keys * #获取所有的key set key value get key del key [key ...] exists key [key ...] append key value strlen key incr key incrby key increment decr key decrby key increment getrange key start end #获取字符串 setrange key offset value #改变字符串 setex key seconds value #设置过期时间 ttl key #查看过期时间 setnx key value #当key不存在的时候才能set mset key value [key value ." />
<meta property="og:type" content="article" />
<meta property="og:url" content="https://xls7771.gitee.io/posts/redis/" />
<meta property="article:published_time" content="2020-10-27T23:36:26+08:00" />
<meta property="article:modified_time" content="2020-10-27T23:36:26+08:00" />
<meta name="twitter:card" content="summary"/>
<meta name="twitter:title" content="Redis"/>
<meta name="twitter:description" content="Redis 去官网上下载redis linux版本的
tar -zxvf 解压redis，然后进入这个解压文件的目录执行make命令 然后再make install
默认安装在usr/local/bin
在usr/local/bin下新建一个myconfig文件夹 mkdir myconfig
然后把redis下的config复制到usr/local/bin/myconfig
redis-server myconfig/redis.conf
redis-cli -p 6379
redis-cli shutdown
redis-check-aof &ndash;fix appendonlu.aof 需要在配置文件中开启aof
ps -ef|grep redis 查看redis进程状态
五大数据类型 String  String
 keys * #获取所有的key set key value get key del key [key ...] exists key [key ...] append key value strlen key incr key incrby key increment decr key decrby key increment getrange key start end #获取字符串 setrange key offset value #改变字符串 setex key seconds value #设置过期时间 ttl key #查看过期时间 setnx key value #当key不存在的时候才能set mset key value [key value ."/>
<meta name="application-name" content="我的Hugo博客">
<meta name="apple-mobile-web-app-title" content="我的Hugo博客"><link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
        <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
        <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"><link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png"><link rel="manifest" href="/site.webmanifest"><link rel="canonical" href="https://xls7771.gitee.io/posts/redis/" /><link rel="prev" href="https://xls7771.gitee.io/posts/hugo-loveit/" /><link rel="next" href="https://xls7771.gitee.io/posts/%E8%BD%AE%E6%92%AD%E5%9B%BE/" /><link rel="stylesheet" href="/lib/normalize/normalize.min.css"><link rel="stylesheet" href="/css/style.min.css"><link rel="stylesheet" href="/lib/fontawesome-free/all.min.css"><link rel="stylesheet" href="/lib/animate/animate.min.css"><script type="application/ld+json">
    {
        "@context": "http://schema.org",
        "@type": "BlogPosting",
        "headline": "Redis",
        "inLanguage": "zh-cn",
        "mainEntityOfPage": {
            "@type": "WebPage",
            "@id": "https:\/\/xls7771.gitee.io\/posts\/redis\/"
        },"genre": "posts","wordcount":  556 ,
        "url": "https:\/\/xls7771.gitee.io\/posts\/redis\/","datePublished": "2020-10-27T23:36:26+08:00","dateModified": "2020-10-27T23:36:26+08:00","publisher": {
            "@type": "Organization",
            "name": "xls"},"author": {
                "@type": "Person",
                "name": "xls"
            },"description": ""
    }
    </script></head>
    <body header-desktop="" header-mobile=""><script type="text/javascript">(window.localStorage && localStorage.getItem('theme') ? localStorage.getItem('theme') === 'dark' : ('' === 'auto' ? window.matchMedia('(prefers-color-scheme: dark)').matches : '' === 'dark')) && document.body.setAttribute('theme', 'dark');</script>

        <div id="mask"></div><div class="wrapper"><header class="desktop" id="header-desktop">
    <div class="header-wrapper">
        <div class="header-title">
            <a href="/" title="我的Hugo博客">我的Hugo博客</a>
        </div>
        <div class="menu">
            <div class="menu-inner"><a class="menu-item" href="/posts/"> 文章 </a><a class="menu-item" href="/tags/"> 标签 </a><a class="menu-item" href="/categories/"> 分类 </a><span class="menu-item delimiter"></span><span class="menu-item search" id="search-desktop">
                        <input type="text" placeholder="搜索文章标题或内容..." id="search-input-desktop">
                        <a href="javascript:void(0);" class="search-button search-toggle" id="search-toggle-desktop" title="搜索">
                            <i class="fas fa-search fa-fw"></i>
                        </a>
                        <a href="javascript:void(0);" class="search-button search-clear" id="search-clear-desktop" title="清空">
                            <i class="fas fa-times-circle fa-fw"></i>
                        </a>
                        <span class="search-button search-loading" id="search-loading-desktop">
                            <i class="fas fa-spinner fa-fw fa-spin"></i>
                        </span>
                    </span><a href="javascript:void(0);" class="menu-item theme-switch" title="切换主题">
                    <i class="fas fa-adjust fa-fw"></i>
                </a>
            </div>
        </div>
    </div>
</header><header class="mobile" id="header-mobile">
    <div class="header-container">
        <div class="header-wrapper">
            <div class="header-title">
                <a href="/" title="我的Hugo博客">我的Hugo博客</a>
            </div>
            <div class="menu-toggle" id="menu-toggle-mobile">
                <span></span><span></span><span></span>
            </div>
        </div>
        <div class="menu" id="menu-mobile"><div class="search-wrapper">
                    <div class="search mobile" id="search-mobile">
                        <input type="text" placeholder="搜索文章标题或内容..." id="search-input-mobile">
                        <a href="javascript:void(0);" class="search-button search-toggle" id="search-toggle-mobile" title="搜索">
                            <i class="fas fa-search fa-fw"></i>
                        </a>
                        <a href="javascript:void(0);" class="search-button search-clear" id="search-clear-mobile" title="清空">
                            <i class="fas fa-times-circle fa-fw"></i>
                        </a>
                        <span class="search-button search-loading" id="search-loading-mobile">
                            <i class="fas fa-spinner fa-fw fa-spin"></i>
                        </span>
                    </div>
                    <a href="javascript:void(0);" class="search-cancel" id="search-cancel-mobile">
                        取消
                    </a>
                </div><a class="menu-item" href="/posts/" title="">文章</a><a class="menu-item" href="/tags/" title="">标签</a><a class="menu-item" href="/categories/" title="">分类</a><a href="javascript:void(0);" class="menu-item theme-switch" title="切换主题">
                <i class="fas fa-adjust fa-fw"></i>
            </a></div>
    </div>
</header>
<div class="search-dropdown desktop">
    <div id="search-dropdown-desktop"></div>
</div>
<div class="search-dropdown mobile">
    <div id="search-dropdown-mobile"></div>
</div>
<main class="main">
                <div class="container"><div class="toc" id="toc-auto">
            <h2 class="toc-title">目录</h2>
            <div class="toc-content" id="toc-content-auto"></div>
        </div><article class="page single"><h1 class="single-title animated flipInX">Redis</h1><div class="post-meta">
            <div class="post-meta-line"><span class="post-author"><a href="/" title="Author" rel=" author" class="author"><i class="fas fa-user-circle fa-fw"></i>xls</a></span></div>
            <div class="post-meta-line"><i class="far fa-calendar-alt fa-fw"></i>&nbsp;<time datetime="2020-10-27">2020-10-27</time>&nbsp;<i class="fas fa-pencil-alt fa-fw"></i>&nbsp;约 556 字&nbsp;
                <i class="far fa-clock fa-fw"></i>&nbsp;预计阅读 3 分钟&nbsp;</div>
        </div><div class="details toc" id="toc-static"  kept="">
                <div class="details-summary toc-title">
                    <span>目录</span>
                    <span><i class="details-icon fas fa-angle-right"></i></span>
                </div>
                <div class="details-content toc-content" id="toc-content-static"><nav id="TableOfContents">
  <ul>
    <li><a href="#string">String</a></li>
    <li><a href="#list">List</a></li>
    <li><a href="#set">Set</a></li>
    <li><a href="#hash">Hash</a></li>
    <li><a href="#zset">Zset</a></li>
  </ul>

  <ul>
    <li><a href="#geospatial">Geospatial</a></li>
    <li><a href="#hyperloglog">Hyperloglog</a></li>
    <li><a href="#bitmap">Bitmap</a></li>
  </ul>

  <ul>
    <li><a href="#缓存穿透查不到">缓存穿透(查不到)</a></li>
    <li><a href="#缓存击穿量太大缓存过期">缓存击穿(量太大，缓存过期！)</a></li>
    <li><a href="#缓存雪崩">缓存雪崩</a></li>
  </ul>
</nav></div>
            </div><div class="content" id="content"><h1 id="redis">Redis</h1>
<p>去官网上下载redis linux版本的</p>
<p>tar -zxvf 解压redis，然后进入这个解压文件的目录执行make命令 然后再make install</p>
<p>默认安装在usr/local/bin</p>
<p>在usr/local/bin下新建一个myconfig文件夹 mkdir myconfig</p>
<p>然后把redis下的config复制到usr/local/bin/myconfig</p>
<p><strong>redis-server myconfig/redis.conf</strong></p>
<p><strong>redis-cli -p 6379</strong></p>
<p><strong>redis-cli shutdown</strong></p>
<p><strong>redis-check-aof &ndash;fix appendonlu.aof</strong> 需要在配置文件中开启aof</p>
<p><strong>ps -ef|grep redis</strong> 查看redis进程状态</p>
<h1 id="五大数据类型">五大数据类型</h1>
<h2 id="string">String</h2>
<blockquote>
<p>String</p>
</blockquote>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">keys * <span class="c1">#获取所有的key</span>

<span class="nb">set</span> key value

get key

del key <span class="o">[</span>key ...<span class="o">]</span>

exists key <span class="o">[</span>key ...<span class="o">]</span>

append key value

strlen key

incr key

incrby key increment

decr key

decrby key increment

getrange key start end <span class="c1">#获取字符串</span>

setrange key offset value <span class="c1">#改变字符串</span>

setex key seconds value <span class="c1">#设置过期时间</span>

ttl key <span class="c1">#查看过期时间</span>

setnx key value <span class="c1">#当key不存在的时候才能set</span>

mset key value <span class="o">[</span>key value ...<span class="o">]</span>

mget key <span class="o">[</span>key ...<span class="o">]</span>

msetnx key value <span class="o">[</span>key value ...<span class="o">]</span> <span class="c1">#原子性操作</span>

getset key value <span class="c1">#先获取key的value如果没有则为空然后set</span>
</code></pre></div><h2 id="list">List</h2>
<blockquote>
<p>List</p>
</blockquote>
<div class="highlight"><pre class="chroma"><code class="language-bash" data-lang="bash">lpush key value <span class="c1">#左推</span>

rpush key value <span class="c1">#右推</span>

lpop key <span class="c1">#左弹</span>

rpop key <span class="c1">#右弹</span>

lrange key <span class="m">0</span> -1 <span class="c1">#全部</span>

llen key <span class="c1">#长度</span>

lrem key count value <span class="c1">#移除 从左到右</span>

ltrim key start stop <span class="c1">#截取 闭区间</span>

rpoplpush <span class="nb">source</span> destination <span class="c1">#soruce列表右弹到destination左推</span>

lset key index value <span class="c1">#修改列表的值</span>

linsert key before<span class="p">|</span>after pivot value <span class="c1">#在元素的前面或者后面添加一个值</span>
</code></pre></div><h2 id="set">Set</h2>
<blockquote>
<p>Set</p>
</blockquote>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="c1">#不允许重复元素</span>

sadd key member <span class="o">[</span>member ...<span class="o">]</span> <span class="c1">#添加member</span>

smembers key <span class="c1">#查看所有member</span>

sismember key member <span class="c1">#判断是否存在member</span>

scard key <span class="c1">#获取set集合中元素的个数</span>

srem key member <span class="o">[</span>member ...<span class="o">]</span> <span class="c1">#移除元素</span>

srandmember <span class="nb">set</span> count <span class="c1">#随机获取元素 count指定个数</span>

spop <span class="c1">#随机删除set集合中的元素</span>

smove <span class="nb">source</span> destination member <span class="c1">#移动source的一个元素到另一个destination中</span>

sdiff key <span class="o">[</span>key ...<span class="o">]</span> <span class="c1">#差集</span>

sinter key <span class="o">[</span>key ...<span class="o">]</span> <span class="c1">#交集</span>

sunion key <span class="o">[</span>key ...<span class="o">]</span> <span class="c1">#并集</span>
</code></pre></div><h2 id="hash">Hash</h2>
<blockquote>
<p>Hash</p>
</blockquote>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">hset key field value <span class="c1">#添加键值对</span>

hget key field <span class="c1">#根据field获取value</span>

hmset key field value <span class="o">[</span>field value ...<span class="o">]</span> <span class="c1">#添加键值对</span>

hmget key field <span class="o">[</span>field ...<span class="o">]</span> <span class="c1">#根据field获取value</span>

hgetall key <span class="c1">#获取所有的键值对</span>

hdel key field <span class="o">[</span>field ...<span class="o">]</span> <span class="c1">#根据field删除</span>

hlen key <span class="c1">#查询有多少组键值对</span>

hexists key field <span class="c1">#是否存在field</span>

hkeys key <span class="c1">#获取所有的field</span>

hvals key <span class="c1">#获取所有的value</span>

hincrby key field increment <span class="c1">#需要Integer类型</span>

hsetnx key field value <span class="c1">#如果存在field则不能set</span>
</code></pre></div><h2 id="zset">Zset</h2>
<blockquote>
<p>Zset</p>
</blockquote>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="c1">#有序集合</span>

zadd key score member <span class="o">[</span>score member<span class="o">]</span> <span class="c1">#注意score和member</span>

zrange key start stop <span class="o">[</span>withscores<span class="o">]</span> <span class="c1">#从小到大排序</span>

zrevrange key start stop <span class="o">[</span>withscores<span class="o">]</span> <span class="c1">#从大到小排序</span>

zrem key member <span class="o">[</span>member ...<span class="o">]</span> <span class="c1">#移除元素</span>

zcard key <span class="c1">#获取有序集合中的元素个数</span>

zcount key min max <span class="c1">#获取score在min到max中的元素个数</span>
</code></pre></div><h1 id="三种特殊数据类型">三种特殊数据类型</h1>
<h2 id="geospatial">Geospatial</h2>
<blockquote>
<p>Geospatial</p>
</blockquote>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="c1">#底层原理其实是Zset</span>

geoadd key longitude latitude member <span class="o">[</span>longitude latitude member ...<span class="o">]</span> <span class="c1">#添加城市的经度和纬度</span>

geopos key member <span class="o">[</span>member<span class="o">]</span> <span class="c1">#获取指定城市的经度和纬度</span>

geodist key member <span class="o">[</span>member<span class="o">]</span> <span class="o">[</span>unit<span class="o">]</span> <span class="c1">#获取指定城市之间的距离 unit的值:m km mi ft 默认是m</span>

georadius key longitude latitude radius m<span class="p">|</span>km<span class="p">|</span>ft<span class="p">|</span>mi <span class="c1">#以这个经纬度为中心半径radius范围之内的城市</span>

georadiusbymember key member radius m<span class="p">|</span>km<span class="p">|</span>ft<span class="p">|</span>mi <span class="c1">#以这个城市为中心半径radius范围之内的城市</span>

geohash key member <span class="o">[</span>member<span class="o">]</span> <span class="c1">#返回城市经纬度的字符串 11个字符的geohash 将二维的经纬度转换成一维的字符串</span>
</code></pre></div><h2 id="hyperloglog">Hyperloglog</h2>
<blockquote>
<p>Hyperloglog</p>
</blockquote>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="c1">#如果允许容错就用Hyperloglog 容错率大概0.81% 如果不允许就用set或者自己的数据类型</span>

pfadd key element <span class="o">[</span>element ...<span class="o">]</span> <span class="c1">#创建元素</span>

pfcount key <span class="o">[</span>key<span class="o">]</span> <span class="c1">#统计元素</span>

pfmerge destkey sourcekey <span class="o">[</span>sourcekey ...<span class="o">]</span> <span class="c1">#合并元素到新的destkey</span>
</code></pre></div><h2 id="bitmap">Bitmap</h2>
<blockquote>
<p>Bitmap</p>
</blockquote>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">setbit key offset value <span class="c1">#使用bitmap记录打卡</span>

getbit key offset <span class="c1">#查询某一天是否打卡</span>

bitcount key <span class="o">[</span>start end<span class="o">]</span> <span class="c1">#统计打卡天数</span>
</code></pre></div><h1 id="事务">事务</h1>
<p><strong>Redis事务没有隔离级别的概念</strong></p>
<p><strong>Redis单条命令式保存原子性的，但是事务不保证原子性</strong></p>
<p><strong>redis的事务:</strong></p>
<ul>
<li>开启事务(multi)</li>
<li>命令入队(&hellip;&hellip;&hellip;)</li>
<li>执行事务(exec)</li>
<li>放弃事务(discard)</li>
</ul>
<blockquote>
<p>事务异常</p>
</blockquote>
<p><strong>编译型异常&ndash;如果命令出现代码错误那么所有命令不会被执行</strong></p>
<p><strong>运行时异常&ndash;错误命令抛出异常，其他命令不受影响</strong></p>
<blockquote>
<p>监控</p>
</blockquote>
<p><strong>悲观锁:</strong></p>
<ul>
<li>很悲观，认为什么时候都会出问题，无论做什么都会加锁！</li>
</ul>
<p><strong>乐观锁:</strong></p>
<ul>
<li>很乐观，认为什么时候都不会出问题，所以不会上锁！更新数据的时候判断，在此期间是否有人修改过这个数据</li>
<li>获取version</li>
<li>更新的时候比较version</li>
</ul>
<blockquote>
<p>Redis监视测试</p>
</blockquote>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">watch key <span class="o">[</span>key ...<span class="o">]</span>

unwatch
</code></pre></div><h1 id="主从复制">主从复制</h1>
<ol>
<li><strong>启动之前先配置注释文件</strong></li>
</ol>
<div class="highlight"><pre class="chroma"><code class="language-xml" data-lang="xml"># port

# pidfile

# logfile

# dbfilename

# requirepass注释掉
</code></pre></div><ol start="2">
<li><strong>启动每一个redis时分别对应每一个redis.conf</strong></li>
</ol>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">redis-server myconfig/redis.conf

info replication
</code></pre></div><ol start="3">
<li><strong>配置主从复制</strong></li>
</ol>
<pre><code class="language-she" data-lang="she">slaveof host port 

info replication
</code></pre><p>上面只是暂时性的</p>
<p>可以在redis.conf里面的replication里面配置持久化</p>
<blockquote>
<p>细节</p>
</blockquote>
<p>主机可以写，从机不能写只能读！主机中的所有信息和数据，都会被从机保存！</p>
<p>测试：主机断开连接，从机依旧连接到主机，但是没有写操作，这个时候，主机如果回来了，从机依旧可以直接获取到主机写的信息！</p>
<p>如果是使用命令行，来配置的主从，这个时候如果重启了，就会变回主机！只要变成从机，立马就会从主机中获取值！</p>
<blockquote>
<p>复制原理</p>
</blockquote>
<p>Slave启动成功连接到master后会发送一个sync同步命令</p>
<p>Master街道命令，启动后台的存盘进程，同时收集所有接收到的用于修改数据集命令，在后台进程执行完毕之后，==master将传送整个数据文件到slave，并完成一次完全同步。==</p>
<p>**全量复制：**slave服务器在接收到数据库文件数据后，将其存盘并加载到内存中。</p>
<p>**增量复制：**Master继续将新的所有收集到的修改命令依次传给slave，完成同步</p>
<p>但是只要是重新连接master，一次完全同步(全量复制)将被自动执行</p>
<blockquote>
<p>谋朝篡位</p>
</blockquote>
<p>如果主机断开了连接，我们可以使用<code>SLAVEOF no one</code>让自己变成主机！其他的结点就可以手动连接到最新的这个主节点(手动)！如果这个时候老大修复了，那就重新连接！</p>
<h1 id="哨兵模式">哨兵模式</h1>
<ol>
<li>配置哨兵配置文件sentinel.conf</li>
</ol>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="c1">#sentinel monitor 被监控的名称 host port 1</span>
sentinel monitor myredis 127.0.0.1 <span class="m">6379</span> <span class="m">1</span>
</code></pre></div><p>数字1，代表主机挂了，slave投票看让谁接替成为主机，票数最多的，就会成为主机！</p>
<ol start="2">
<li>启动哨兵</li>
</ol>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">redis-sentinel myconfig/sentinel.conf
</code></pre></div><p>如果Master节点断开了，就会在从机中随机选择一个服务器！</p>
<p>如果主机此时回来了，只能归并到新的主机下，当作从机，这就是哨兵模式的规则！</p>
<blockquote>
<p>哨兵模式</p>
</blockquote>
<p>优点：</p>
<ol>
<li>哨兵集群，基于主从复制，所有的主从配置优点，它全有</li>
<li>主从可以切换，故障可以转移，系统的可用性就会更好</li>
<li>哨兵模式就是主从模式的升级，手动到自动，更加健壮！</li>
</ol>
<p>缺点：</p>
<ol>
<li>Redis不好在线扩容，集群容量一旦达到上限，在线扩容就十分麻烦！</li>
<li>实现哨兵模式的配置其实是很麻烦的，里面有很多选择！</li>
</ol>
<blockquote>
<p>哨兵模式的全部配置</p>
</blockquote>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"><span class="c1">#哨兵sentinel实例运行的端口 默认26379</span>
port <span class="m">26379</span>

<span class="c1">#哨兵sentinel的工作目录</span>
dir /tmp

<span class="c1">#master-name 可以自己命名主节点名字</span>
<span class="c1">#quorum 配置多少个sentinel哨兵统一认为master主节点失联 那么这时客观上认为主节点失联了</span>
<span class="c1">#sentinel monitor &lt;master-name&gt; &lt;ip&gt; &lt;redis-port&gt; &lt;quorum&gt;</span>
sentinel monitor mymaster 127.0.0.1 <span class="m">6379</span> <span class="m">2</span>

<span class="c1">#设置哨兵sentinel 连接主从的密码 注意必须为主从设置一样的验证密码</span>
<span class="c1">#sentinel auth-pass &lt;master-name&gt; &lt;password&gt;</span>
sentinel auth-pass mymaster MySUPER--secret-0123password

<span class="c1">#指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认30秒</span>
<span class="c1">#sentinel down-after-milliseconds &lt;master-name&gt; &lt;milliseconds&gt;</span>
sentinel down-after-milliseconds mymaster <span class="m">30000</span>

<span class="c1">#......</span>
</code></pre></div><h1 id="缓存穿透和雪崩">缓存穿透和雪崩</h1>
<h2 id="缓存穿透查不到">缓存穿透(查不到)</h2>
<blockquote>
<p>概念</p>
</blockquote>
<p>用户查询一个数据发现redis内存数据库没有，于是向持久层数据库查询。发现也美誉，于是本次查询失败。当用户很多的时候，缓存都没有命中，于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力，这时候就相当于出现了缓存穿透。</p>
<blockquote>
<p>解决方案</p>
</blockquote>
<p><strong>布隆过滤器</strong></p>
<p>布隆过滤器是一种数据结构，对所有可能查询的参数以hash形式存储，在控制层先进行校验，不符合则丢弃，从而避免了对底层存储系统的查询压力</p>
<h2 id="缓存击穿量太大缓存过期">缓存击穿(量太大，缓存过期！)</h2>
<blockquote>
<p>概述</p>
</blockquote>
<p>缓存击穿，是指一个key非常热点，在不停的扛着大并发，大并发集中对这一个热点进行访问，当这个key在失效的瞬间，持续的大并发就穿破缓存，直接请求数据库，就像在一个屏障上凿开了一个洞。</p>
<p>当某个key在过期的瞬间，有大量的请求并发访问，这类数据一般是热点数据，由于缓存过期，会同时访问数据库来查询最新数据，并且回写缓存，会导致数据库瞬间压力过大。</p>
<blockquote>
<p>解决方案</p>
</blockquote>
<p><strong>设置热点数据永不过期</strong></p>
<p>从缓存层面来看，没有设置过期时间，所以不会出现热点key过期后产生的问题。</p>
<p><strong>加互斥锁</strong></p>
<p>分布式锁：使用分布式锁，保证对于每个key同时只有一个线程去查询后端服务，其他线程没有获得分布式锁的权限，因此只需要等待即可。这种分布式将高并发的压力转移到了分布式锁，因此对分布式锁的考验很大。</p>
<h2 id="缓存雪崩">缓存雪崩</h2>
<blockquote>
<p>概念</p>
</blockquote>
<p>缓存雪崩，是指在某一个时间段，缓存集中过期失效。Redis宕机！</p>
<p>产生雪崩的原因之一，比如在写本文的时候，马上就要到双十二零点，很快就会迎来一波抢购，这波商品时间比较集中的放入了缓存，假设缓存一小时。那么到了凌晨一点钟的时候，这批商品的缓存就都过期了。而对这批商品的访问查询，都落到了数据库上，对于数据库而言，就会产生周期性的压力波峰。于是所有的请求都会达到存储层，存储层的调用量会暴增，造成存储层也会挂掉的情况。</p>
<blockquote>
<p>解决方案</p>
</blockquote>
<p><strong>redis高可用</strong></p>
<p>这个思想的含义是，既然redis有可能挂掉，那我多增设几台redis，这样一台挂掉之后其他的还可以继续工作，其实就是搭建的集群。(异地多活！)</p>
<p><strong>限流降级</strong></p>
<p>这个解决方案的思想是，在缓存失效后，通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存，其他线程等待。</p>
<p><strong>数据预热</strong></p>
<p>数据加热的含义就是在正式部署之前，我先把可能的数据先预先访问一边，这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key，设置不同的过期时间，让缓存失效的时间点尽量均匀。</p>
</div><div class="post-footer" id="post-footer">
    <div class="post-info">
        <div class="post-info-line">
            <div class="post-info-mod">
                <span>更新于 2020-10-27</span>
            </div>
            <div class="post-info-license"></div>
        </div>
        <div class="post-info-line">
            <div class="post-info-md"></div>
            <div class="post-info-share">
                <span><a href="javascript:void(0);" title="分享到 Twitter" data-sharer="twitter" data-url="https://xls7771.gitee.io/posts/redis/" data-title="Redis"><i class="fab fa-twitter fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Facebook" data-sharer="facebook" data-url="https://xls7771.gitee.io/posts/redis/"><i class="fab fa-facebook-square fa-fw"></i></a><a href="javascript:void(0);" title="分享到 Buffer" data-sharer="buffer" data-url="https://xls7771.gitee.io/posts/redis/" data-title="Redis"><i class="fab fa-buffer fa-fw"></i></a><a href="javascript:void(0);" title="分享到 百度" data-sharer="baidu" data-url="https://xls7771.gitee.io/posts/redis/" data-title="Redis"><i data-svg-src="/lib/simple-icons/icons/baidu.min.svg"></i></a></span>
            </div>
        </div>
    </div>

    <div class="post-info-more">
        <section class="post-tags"></section>
        <section>
            <span><a href="javascript:void(0);" onclick="window.history.back();">返回</a></span>&nbsp;|&nbsp;<span><a href="/">主页</a></span>
        </section>
    </div>

    <div class="post-nav"><a href="/posts/hugo-loveit/" class="prev" rel="prev" title="Hugo LoveIt"><i class="fas fa-angle-left fa-fw"></i>Hugo LoveIt</a>
            <a href="/posts/%E8%BD%AE%E6%92%AD%E5%9B%BE/" class="next" rel="next" title="轮播图">轮播图<i class="fas fa-angle-right fa-fw"></i></a></div>
</div>
</article></div>
            </main><footer class="footer">
        <div class="footer-container"><div class="footer-line">由 <a href="https://gohugo.io/" target="_blank" rel="noopener noreffer" title="Hugo 0.74.2">Hugo</a> 强力驱动 | 主题 - <a href="https://github.com/dillonzq/LoveIt" target="_blank" rel="noopener noreffer" title="LoveIt 0.2.10"><i class="far fa-kiss-wink-heart fa-fw"></i> LoveIt</a>
                </div><div class="footer-line"><i class="far fa-copyright fa-fw"></i><span itemprop="copyrightYear">2020</span><span class="author" itemprop="copyrightHolder">&nbsp;<a href="/" target="_blank">xls</a></span></div>
        </div>
    </footer></div>

        <div id="fixed-buttons"><a href="#" id="back-to-top" class="fixed-button" title="回到顶部">
                <i class="fas fa-arrow-up fa-fw"></i>
            </a><a href="#" id="view-comments" class="fixed-button" title="查看评论">
                <i class="fas fa-comment fa-fw"></i>
            </a>
        </div><script type="text/javascript" src="/lib/smooth-scroll/smooth-scroll.min.js"></script><script type="text/javascript" src="/lib/autocomplete/autocomplete.min.js"></script><script type="text/javascript" src="/lib/lunr/lunr.min.js"></script><script type="text/javascript" src="/lib/lunr/lunr.stemmer.support.min.js"></script><script type="text/javascript" src="/lib/lunr/lunr.zh.min.js"></script><script type="text/javascript" src="/lib/lazysizes/lazysizes.min.js"></script><script type="text/javascript" src="/lib/clipboard/clipboard.min.js"></script><script type="text/javascript" src="/lib/sharer/sharer.min.js"></script><script type="text/javascript">window.config={"code":{"copyTitle":"复制到剪贴板","maxShownLines":10},"comment":{},"search":{"highlightTag":"em","lunrLanguageCode":"zh","lunrSegmentitURL":"/lib/lunr/lunr.segmentit.js","maxResultLength":10,"noResultsFound":"没有找到结果","snippetLength":30}};</script><script type="text/javascript" src="/js/theme.min.js"></script></body>
</html>
